package com.dxy.yzs.marathon.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dxy.yzs.marathon.common.Constants;
import com.dxy.yzs.marathon.domain.MessageContact;
import com.dxy.yzs.marathon.domain.MessageContent;
import com.dxy.yzs.marathon.domain.MessageRelation;
import com.dxy.yzs.marathon.domain.User;
import com.dxy.yzs.marathon.mapper.ImMsgContactMapper;
import com.dxy.yzs.marathon.mapper.ImMsgContentMapper;
import com.dxy.yzs.marathon.mapper.ImMsgRelationMapper;
import com.dxy.yzs.marathon.mapper.UserMapper;
import com.dxy.yzs.marathon.service.ImMsgContentService;
import com.dxy.yzs.marathon.service.MessageService;
import com.dxy.yzs.marathon.vo.MessageContactVO;
import com.dxy.yzs.marathon.vo.MessageVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class MessageServiceImpl implements MessageService {
    @Autowired
    private ImMsgContentMapper contentMapper;
    @Autowired
    private ImMsgRelationMapper relationMapper;
    @Autowired
    private ImMsgContactMapper contactMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public MessageVO sendNewMsg(int senderUid, int recipientUid, String content, int msgType) {
        Date currentTime = new Date();
        /**存内容*/
        MessageContent messageContent = new MessageContent();
        messageContent.setSenderId(senderUid);
        messageContent.setRecipientId(recipientUid);
        messageContent.setContent(content);
        messageContent.setMsgType(msgType);
        messageContent.setCreateTime(currentTime);
        contentMapper.insert(messageContent);
        Integer mid = messageContent.getMid();

        /**存发件人的发件箱*/
        MessageRelation messageRelationSender = new MessageRelation();
        messageRelationSender.setMid(mid);
        messageRelationSender.setOwnerUid(senderUid);
        messageRelationSender.setOtherUid(recipientUid);
        messageRelationSender.setType(0);
        messageRelationSender.setCreateTime(currentTime);
        relationMapper.insert(messageRelationSender);

        /**存收件人的收件箱*/
        MessageRelation messageRelationRecipient = new MessageRelation();
        messageRelationRecipient.setMid(mid);
        messageRelationRecipient.setOwnerUid(recipientUid);
        messageRelationRecipient.setOtherUid(senderUid);
        messageRelationRecipient.setType(1);
        messageRelationRecipient.setCreateTime(currentTime);
        relationMapper.insert(messageRelationRecipient);

        /**更新发件人的最近联系人
         * ownerUid  owner_uid ---- senderUid
         * otherUid  other_uid ---- recipientUid
         * */
        MessageContact messageContactSender = contactMapper.selectOne(
                new QueryWrapper<MessageContact>()
                        .eq("owner_uid",senderUid)
                        .eq("other_uid",recipientUid)
        );
        if (messageContactSender != null) {
            messageContactSender.setMid(mid);
            contactMapper.updateById(messageContactSender);
        } else {
            messageContactSender = new MessageContact();
            messageContactSender.setOwnerUid(senderUid);
            messageContactSender.setOtherUid(recipientUid);
            messageContactSender.setMid(mid);
            messageContactSender.setCreateTime(currentTime);
            messageContactSender.setType(0);
            contactMapper.insert(messageContactSender);
        }

        /**更新收件人的最近联系人
         *  ownerUid  owner_uid ---- recipientUid
         *  otherUid  other_uid ---- senderUid
         * */
        MessageContact messageContactRecipient = contactMapper.selectOne(
                new QueryWrapper<MessageContact>()
                        .eq("owner_uid",recipientUid)
                        .eq("other_uid",senderUid)
        );
        if (messageContactRecipient != null) {
            messageContactRecipient.setMid(mid);
            contactMapper.updateById(messageContactRecipient);
        } else {
            messageContactRecipient = new MessageContact();
            messageContactRecipient.setOwnerUid(recipientUid);
            messageContactRecipient.setOtherUid(senderUid);
            messageContactRecipient.setMid(mid);
            messageContactRecipient.setCreateTime(currentTime);
            messageContactRecipient.setType(1);
            contactMapper.insert(messageContactRecipient);
        }

        /**更未读更新 */
        redisTemplate.opsForValue().increment(recipientUid + "_T", 1); //加总未读
        redisTemplate.opsForHash().increment(recipientUid + "_C", senderUid, 1); //加会话未读


        /** 待推送消息发布到redis */
        User self = userMapper.selectById(senderUid);
        User other = userMapper.selectById(recipientUid);
        MessageVO messageVO = new MessageVO(mid, content, self.getId(), messageContactSender.getType(), other.getId(), messageContent.getCreateTime(), self.getAvatar(), other.getAvatar(), self.getUsername(), other.getUsername());
        redisTemplate.convertAndSend(Constants.WEBSOCKET_MSG_TOPIC, JSONUtil.toJsonStr(messageVO));

        return messageVO;
    }

    @Override
    public List<MessageVO> queryConversationMsg(long ownerUid, long otherUid) {
        List<MessageRelation> relationList =  relationMapper.selectList(
                new QueryWrapper<MessageRelation>()
                    .eq("owner_uid",ownerUid)
                    .eq("other_uid",otherUid)
                    .orderByAsc("mid")
        );
        return composeMessageVO(relationList, ownerUid, otherUid);
    }


    @Override
    public MessageContactVO queryContacts(long ownerUid) {
        List<MessageContact> contacts = contactMapper.selectList(
                new QueryWrapper<MessageContact>()
                    .eq("owner_uid",ownerUid)
                    .orderByDesc("mid")
        );
        if (contacts != null) {
            User user = userMapper.selectById(ownerUid);
            long totalUnread = 0;
            Object totalUnreadObj = redisTemplate.opsForValue().get(user.getId() + Constants.TOTAL_UNREAD_SUFFIX);
            if (null != totalUnreadObj) {
                totalUnread = Long.parseLong((String) totalUnreadObj);
            }

            MessageContactVO contactVO = new MessageContactVO(user.getId(), user.getUsername(), user.getAvatar(), totalUnread);
            contacts.stream().forEach(contact -> {
                Integer mid = contact.getMid();
                MessageContent contentVO = contentMapper.selectById(mid);
                User otherUser = userMapper.selectById(contact.getOtherUid());

                if (null != contentVO) {
                    long convUnread = 0;
                    Object convUnreadObj = redisTemplate.opsForHash().get(user.getId() + Constants.CONVERSION_UNREAD_SUFFIX, otherUser.getId());
                    if (null != convUnreadObj) {
                        convUnread = Long.parseLong((String) convUnreadObj);
                    }
                    MessageContactVO.ContactInfo contactInfo = contactVO.new ContactInfo(otherUser.getId(), otherUser.getUsername(), otherUser.getAvatar(), mid, contact.getType(), contentVO.getContent(), convUnread, contact.getCreateTime());
                    contactVO.appendContact(contactInfo);
                }
            });
            return contactVO;
        }
        return null;
    }


    @Override
    public List<MessageVO> queryNewerMsgFrom(long ownerUid, long otherUid, long fromMid) {
        List<MessageRelation> relationList =  relationMapper.selectList(
                new QueryWrapper<MessageRelation>()
                        .eq("owner_uid",ownerUid)
                        .eq("other_uid",otherUid)
                        .gt("mid",fromMid)
                        .orderByAsc("mid")
        );
        return composeMessageVO(relationList, ownerUid, otherUid);
    }


    @Override
    public long queryTotalUnread(long ownerUid) {
        long totalUnread = 0;
        Object totalUnreadObj = redisTemplate.opsForValue().get(ownerUid + Constants.TOTAL_UNREAD_SUFFIX);
        if (null != totalUnreadObj) {
            totalUnread = Long.parseLong((String) totalUnreadObj);
        }
        return totalUnread;
    }


    private List<MessageVO> composeMessageVO(List<MessageRelation> relationList, long ownerUid, long otherUid) {
        if (null != relationList && !relationList.isEmpty()) {
            /** 先拼接消息索引和内容 */
            List<MessageVO> msgList = new ArrayList<>();
            User self = userMapper.selectById(ownerUid);
            User other = userMapper.selectById(otherUid);
            relationList.stream().forEach(relation -> {
                Integer mid = relation.getMid();
                MessageContent contentVO = contentMapper.selectById(mid);
                if (null != contentVO) {
                    String content = contentVO.getContent();
                    MessageVO messageVO = new MessageVO(mid, content, relation.getOwnerUid(), relation.getType(), relation.getOtherUid(), relation.getCreateTime(), self.getAvatar(), other.getAvatar(), self.getUsername(), other.getUsername());
                    msgList.add(messageVO);
                }
            });

            /** 再变更未读 */
            Object convUnreadObj = redisTemplate.opsForHash().get(ownerUid + Constants.CONVERSION_UNREAD_SUFFIX, otherUid);
            if (null != convUnreadObj) {
                long convUnread = Long.parseLong((String) convUnreadObj);
                redisTemplate.opsForHash().delete(ownerUid + Constants.CONVERSION_UNREAD_SUFFIX, otherUid);
                long afterCleanUnread = redisTemplate.opsForValue().increment(ownerUid + Constants.TOTAL_UNREAD_SUFFIX, -convUnread);
                /** 修正总未读 */
                if (afterCleanUnread <= 0) {
                    redisTemplate.delete(ownerUid + Constants.TOTAL_UNREAD_SUFFIX);
                }
            }
            return msgList;
        }
        return null;
    }
}
